﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;

namespace SimpleDataAccessConsole.DataAccessLayer
{
	public class Database
	{
		public Database(string providerName, string connectionString)
		{
			ProviderName = providerName;
			ConnectionString = connectionString;
		}

		public string ProviderName { get; private set; }

		public string ConnectionString { get; private set; }

		public IDbConnection Connection
		{
			get { return ConnectionProvider(ProviderName, ConnectionString); }
		}

		public IDbConnection ConnectionProvider(string providerName, string connectionString)
		{
			var provider = DbProviderFactories.GetFactory(providerName);
			var connection = provider.CreateConnection();
			if (connection != null)
			{
				connection.ConnectionString = connectionString;
				return connection;
			}
			throw new ArgumentException("could not create connection from provider", providerName);
		}

		public virtual IEnumerable<object[]> Execute(SimpleQuery query)
		{
			using (var connection = Connection)
			using (var command = connection.CreateCommand().CreateCommand(query))
			{
				command.Connection = connection;
				connection.Open();

				using (var reader = command.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.CloseConnection))
				{
					var result = new Object[reader.FieldCount];

					// turn the reader into an enumerable
					while (reader.Read())
					{
						reader.GetValues(result);
						yield return result;
					}

				}
			}
		}

		public virtual IEnumerable<string> GetFields(SimpleQuery query)
		{
			using (var connection = Connection)
			using (var command = connection.CreateCommand().CreateCommand(query))
			{
				command.Connection = connection;
				connection.Open();

				using (var reader = command.ExecuteReader(CommandBehavior.SchemaOnly | CommandBehavior.CloseConnection))
				{
					for (var i = 0; i <= reader.FieldCount - 1; i++)
					{
						yield return reader.GetName(i);
					}
				}
			}
		}

        public dynamic Execute(SimpleQuery query, Func<IDataReader, dynamic> func)
        {
            dynamic result;
            using (var connection = Connection)
            using (var command = connection.CreateCommand().CreateCommand(query))
            {
                command.Connection = connection;
                connection.Open();

                using (var reader = command.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.CloseConnection))
                {
                    result = func(reader);
                }
            }
            return result;
        }
	}
}